1

I have a program where I use custom message to call some methods from WndProc, like this:

protected override void WndProc(ref Message m)
{
    switch ((uint)m.Msg)
    {
        case WM_QUIT:
            Application.Exit();
            return;
        case WM_STARTOP:
            Context.TændNas();
            m.Result = new IntPtr(1);
            break;
    }
    base.WndProc(ref m);
}

Now I want to make the methods asynchronous. However, I can't add the async keyword to the WndProc override.

If I make Context.TændNasAsync an async method, how can I call it from WndProc?

Conclusion:

I go for @Hans Passant's suggestion, creating an async eventhandler. That way I can call the async method on the UI thread, while keeping it asynchron (awaitable).

Poul Bak
  • 10,450
  • 5
  • 32
  • 57
  • 1
    WndProc() normally raises an event to allow the client code to respond to the message. You can do that as well here to get an async void event handler. Beware the [consequences of such handlers](https://stackoverflow.com/questions/14464391/how-to-avoid-reentrancy-with-async-void-event-handlers). – Hans Passant Sep 19 '18 at 11:54
  • You should newer run something that takes too much time from a message processing function. You can only start a task, or create a background worker, but do not block the GUI thread... This is not a good idea and can cause unforeseen behaviour. – Julo Sep 19 '18 at 12:10
  • @julo, that is not correct, Windows forms is based on messages, even long running tasks are started by for instance a button click message. – Poul Bak Sep 19 '18 at 12:13
  • @PoulBak: I know it is possible, but you should no do this. The GUI will stop responding and it can cause confusion *(for user)*, or, in the worst case, the OS can terminate the application. *(The application XY do not respond. Stop/close the application? - window)* – Julo Sep 19 '18 at 12:16

2 Answers2

3

This should work:

Task.Run(()=>Context.TaendNas());

or rather:

Task.Run(async ()=> await Context.TaendNas());
Adam Jachocki
  • 1,897
  • 1
  • 12
  • 28
  • Won't that be 'fire and forget' ? – Poul Bak Sep 19 '18 at 11:53
  • You can always try to add .Wait() method at the end of task run: Task.Run(...).Wait(); But the question was how to run async method from synch context – Adam Jachocki Sep 19 '18 at 11:55
  • Can't access UI controls using this method! – Poul Bak Sep 19 '18 at 12:00
  • 1
    Of course you can. But to do that you must be sure that you are accessing UI control from UI thread. Not from any thread. You can do it using Invoke. But this is completely different story. – Adam Jachocki Sep 19 '18 at 13:08
  • 1
    Wrapping the synchronous method in `Task.Run` does not help here and changes the behavior of `WndProc` in ways a consumer can't handle, i.e. the method will return before it finishes. Your secodn sample doesn't work either since `TaendNas` doesn't return a `Task` to begin with. – JSteward Sep 19 '18 at 16:41
0

You can use events:

event EventHandler onStartOp;
protected override void WndProc(ref Message m)
{
    switch ((uint)m.Msg)
    {
        case WM_STARTOP:
            onStartOp(this, EventArgs.Empty);
            break;
    }
    base.WndProc(ref m);
}

Somewhere in your code:

 onStartOp+= async (s, e) => await Context.TændNas();
tigrou
  • 4,236
  • 5
  • 33
  • 59