Is there a non-blocking version of MessageBox.Show (or something like it)?

Dan Tao picture Dan Tao · May 14, 2010 · Viewed 17.4k times · Source

Long-delayed update

I'm accepting MUG4N's answer to this question, and I also want to respond to some of the criticisms that were raised against it.

ChrisF said:

...you can't make UI calls directly from background threads.

This is a blanket statement, and is not 100% true. Let me just point out a few facts:

  1. You can actually make UI calls all you want if you set Control.CheckForIllegalCrossThreadCalls = false. "Ack!" I hear you saying. "Don't ever do that!" Yes, yes -- but why? The answer: because sometimes this will corrupt memory.

    The control classes in System.Windows.Forms are not written to be thread-safe, so sometimes updating them from background threads can corrupt memory. But if this only sometimes happens and not always, what this tells me is that it is not the calling of UI code per se, but rather the potentially unsafe collision of UI code that can cause exceptions.

  2. To reinforce point 1, consider this: the "safe" way to invoke UI code from a background thread is to do so using Control.Invoke or Control.BeginInvoke, right? But this is a UI call; it's just the UI call we're supposed to make if we're updating the GUI from a non-GUI thread. What I mean is, clearly, it is not simply invoking "any" method on a Control object from an outside thread that's going to cause chaos (if that were the case, then we couldn't even call Invoke and we'd be stuck completely). Again, it's the potential collision of separate UI calls that cannot safely occur simultaneously that will prove destructive.

  3. Keeping the above two points in mind, ask yourself: why would it be unsafe to call MessageBox.Show from a non-GUI thread? A completely separate Form is created and displayed; its properties do not in any way interact with any other existing GUI object; in fact, it cannot be accessed anywhere in any manner, except for one: from the calling thread, which accesses its DialogResult property (and only that via the Show method's return value).

Moving along. Conrad Albrecht said:

...given the assertion that Show() sets up its own message pump in Dan's ref'd topic, (which was not substantiated, but which I can't refute)...

This is a totally fair point (though I personally hold Jared Par in high enough esteem that I wouldn't generally be inclined to doubt what he says). In any case, a peek at the MessageBox.Show method through Reflector reveals this snippet:

Application.BeginModalMessageLoop();
try
{
    result = Win32ToDialogResult(SafeNativeMethods.MessageBox(new HandleRef(owner, zero), text, caption, type));
}
finally
{
    Application.EndModalMessageLoop();
    UnsafeNativeMethods.ThemingScope.Deactivate(userCookie);
}

A further peek into the Application.BeginModalMessageLoop method reveals this:

ThreadContext.FromCurrent().BeginModalMessageLoop(null);

And this ThreadContext.FromCurrent, in turn:

// [Reflector shows that currentThreadContext is a ThreadStatic member. -Dan]
if (currentThreadContext == null)
{
    currentThreadContext = new Application.ThreadContext();
}
return currentThreadContext;

I don't know enough about these lower-level Windows constructs to fully understand this code, but this seems to me to be evidence of exactly what Jared was saying in the answer I referenced in my old comment (for curious readers: Does MessageBox.Show() automatically marshall to the UI Thread?).

So, yeah. I am totally in agreement with MUG4N on this one.

(If anyone can convincingly argue that I am still mistaken here, please speak up. Although I feel I've made a pretty good case for why I believe MUG4N is right, I'm obviously not 100% certain.)


Original question

Often you just want to notify the user that something has occurred, but there's really no need for any input from them. In this common scenario, I sometimes see code like this:

MessageBox.Show("Something has occurred", "Something", MessageBoxButtons.OK);

This code, as we all know, causes a little pop-up window to appear with only an OK button. Now here's the thing: this code blocks (the UI thread). But in the vast majority of cases, it seems to me, if you only have an OK button, there's very little need to block. (Isn't the purpose of blocking typically to receive some input from the user? And if the user's only choice is "OK," in this typical case, isn't blocking pretty pointless?)

Obviously I could just write my own little form that does basically exactly what MessageBox.Show does, except that it returns nothing (no DialogResult) and doesn't block. But I was just wondering if something like this exists already that I didn't know about.

Answer

MUG4N picture MUG4N · May 14, 2010

You need to use multi threading to perform this task in which one thread (the main thread) will do the processing and the other thread will be used to show the messagebox.