Introduction

The .NET standard MessageBox is centered on the screen area, not on the application. This code contains a simple component which uses a hook to center the MessageBox and also other CommonDialog or Forms on the application area.

Background

This article will not explain in detail how to use a hook in a window. The component will add a WH_CALLWNDPROC hook looking for a WM_INITDIALOG message before opening the dialog. When this message occurs, the window is centered on the owner window, or the active window if the owner window is null.

Using the code

Using the code is very easy. It is the same as using the standard MessageBox.

The following static methods are available:

DlgBox.ShowDialog(...)

For CommonDialog and Forms.

MsgBox.Show(...)

For standard MessageBox, you can define the caption.

AppBox.Show(...)

For standard MessageBox with Application.ProductName as caption.

ErrBox.Show(...)

For standard error MessageBox with message or exception.

Example: the following code displays a centered OpenFileDialog:

DlgBox.ShowDialog(new OpenFileDialog());

Example: the following code display a centered exception error message:

try
{
...
}
catch (Exception ex)
{
ErrBox.Show(ex);
}

It is possible to add standard buttons or icons. All the MessageBox methods are wrapped.

Points of Interest

There is a base class WindowsHook to create other hooks. The WndProcRetHook is based on this class. You can use this base class to create your own hook.

There is also a TrueScreenRect property to retrieve the true screen size on multiscreen display.

History

This version is working well since 1.1.2003.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

I am not a WinAPI guru by any means, but this code was just too cool to not update it. (Plus I needed it badly to center the ColorDialog for a project I'm working on. LOL).

So I got it working on 64-bit Windows 7. Essentially, the fix (as I understand it - again, I don't usually spelunk in the WinAPI caves) involves the size allocated in the structure to receive lparam, lresult, wparam, etc. These were noted as "int" in the original code, but with 64-bit Windows (from my research on the InterWebs) they need to be IntPtr (8-byte, not 4-byte - or something like that).

I am more than willing to ZIP up the code and re-post it. Does anyone know how I do that from the forum Q&A? I have posted some original stuff to codeproject, but I have never posted a code attachment from the forum Q&A.

So long story short: I got this bad boy working with 64-bit Windows 7, and it works as advertised. MUCH karma to the OP. I did essentially nothing but update a few struct record sizes. In fact, the code was so insanely complex that I decided I had to try and update it. There was no way I wanted to start from scratch!

I can't seem to get this to work with the FolderBrowserDialog. Works fine otherwise. I tried listening for WM_SHOWWINDOW, but that didn't help either. I can see the code getting called, but the dialog is never centered.

When I compile the Centering MessageBox into my project I get the following warning: 'System.AppDomain.GetCurrentThreadId()' is obsolete: 'AppDomain.GetCurrentThreadId has been deprecated because it does not provide a stable Id when managed threads are running on fibers (aka lightweight threads). To get a stable identifier for a managed thread, use the ManagedThreadId property on Thread. http://go.microsoft.com/fwlink/?linkid=14202'

I tried with Thread.CurrentThread.ManagedThreadId but I don’t seem to work. Does anyone have a solution for this?

We had some machines where the messages boxes were not centering. I determined that under certain desktop configurations the WM_INITDIALOG messages is never sent. All I had to do was also look for the WM_SHOWWINDOW messages. If the WM_INITDIALOG is not sent the WM_SHOWWINDOW will be sent instead. The change went in the CenterWindow class WndProcRet routine. I'd share the code but I've converted your project of VB.

We've been using your classes for some time and greatly appreciate them.

I had implemented this code in VS 2003 and everything worked great. But after we upgraded to VS2005, the WindowActivate event does not get fired and hence the messagebox is always centering on the screen. Any thoughts on why this might be happening?

Vinod Rodrigo

-- modified at 12:59 Thursday 15th June, 2006

-updateThe difference between the codebases is in public void Install(){ hHook = SetWindowsHookEx(hookType, filterFunc, IntPtr.Zero, (int)AppDomain.GetCurrentThreadId());}MS deprecated AppDomain.GetCurrentThreadId substituting it with Thread.CurrentThread.ManagedThreadId, so now hHook = 0 with the new call

Been playing with thsi class under Vista SP1 and VS2008. You're right - the hook handle is always 0. Reverted to the prior code ie. (int)AppDomain.GetCurrentThreadId(), and lo-&-behold, it works as it should...my suggestion - just ignore the compile warning for now....

just looked at the code, its pretty nice...; adding a private contructor to hide from the documentation is a good trick! I recompiled for .NET 2.0 without problems. The *very* first time I ran the 'Show Open File Dialog', I had a bit of an unwanted animation: the box flashed in the middle of the screen, and then re-centered above the test application. The flash disappeared running it the second time (not that I mind, I'm just curious as to why this might happen).

I also encounter this question, The every first time I ran the 'Show Open File Dialog', I had a bit of an unwanted animation: the box flashed in the middle of the screen, and then be moved to center of the test application.