Let me give you the background.
We have an Application(medium sized) that is using MessageBox.Show (....) at various places (in hundreds).
These message bo
Here is a piece of code based on UIAutomation (a cool but still not very used API) that attempts to close all modal windows (including the one opened with MessageBox) of the current process:
/// <summary>
/// Attempt to close modal windows if there are any.
/// </summary>
public static void CloseModalWindows()
{
// get the main window
AutomationElement root = AutomationElement.FromHandle(Process.GetCurrentProcess().MainWindowHandle);
if (root == null)
return;
// it should implement the Window pattern
object pattern;
if (!root.TryGetCurrentPattern(WindowPattern.Pattern, out pattern))
return;
WindowPattern window = (WindowPattern)pattern;
if (window.Current.WindowInteractionState != WindowInteractionState.ReadyForUserInteraction)
{
// get sub windows
foreach (AutomationElement element in root.FindAll(TreeScope.Children, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Window)))
{
// hmmm... is it really a window?
if (element.TryGetCurrentPattern(WindowPattern.Pattern, out pattern))
{
// if it's ready, try to close it
WindowPattern childWindow = (WindowPattern)pattern;
if (childWindow.Current.WindowInteractionState == WindowInteractionState.ReadyForUserInteraction)
{
childWindow.Close();
}
}
}
}
}
For example, if you have a WinForms application that pops up a MessageBox when you press some button1, you will still be able to close the app using Windows "Close Window" menu (right click in the task bar):
private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show("Don't click me. I want to be closed automatically!");
}
protected override void WndProc(ref System.Windows.Forms.Message m)
{
const int WM_SYSCOMMAND = 0x0112;
const int SC_CLOSE = 0xF060;
if (m.Msg == WM_SYSCOMMAND) // this is sent even if a modal MessageBox is shown
{
if ((int)m.WParam == SC_CLOSE)
{
CloseModalWindows();
Close();
}
}
base.WndProc(ref m);
}
You could use CloseModalWindows somewhere else in your code of course, this is just a sample.
This link on MSDN forums shows how to close a message box by using FindWindow
and sending a WM_CLOSE
message. Although the question was asked for .NET/WindowsCE, it might solve your problem, its worth a look
Refer to DmitryG post in "Close a MessageBox after several seconds"
Auto-Close MessageBox after timeout reach
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;
public class AutoClosingMessageBox
{
System.Threading.Timer _timeoutTimer;
string _caption;
AutoClosingMessageBox(string text, string caption, int timeout)
{
_caption = caption;
_timeoutTimer = new System.Threading.Timer(OnTimerElapsed,
null, timeout, System.Threading.Timeout.Infinite);
MessageBox.Show(text, caption);
}
public static void Show(string text, string caption, int timeout)
{
new AutoClosingMessageBox(text, caption, timeout);
}
void OnTimerElapsed(object state)
{
IntPtr mbWnd = FindWindow(null, _caption);
if (mbWnd != IntPtr.Zero)
SendMessage(mbWnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
_timeoutTimer.Dispose();
}
const int WM_CLOSE = 0x0010;
[System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
}
and Call it via
AutoClosingMessageBox.Show("Content", "Title", TimeOut);
I used .net 2 and two approaches with the same trick.
Open the MessageBox from stub-Form with MessageBox.Show(this,"message")
When the form is not visible or doesn't has really UI.
Keep the form handler and close it with:
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
or
holding the form as class parameter and using FormX.Close()
.
Since the Form is the owner of the MessageBox, Closing it will close the MessageBox.
Heres my example with SendKeys - tested and working:
lets say we have backgroundworker and button in form. After button was click - start worker and show message box. In workers DoWork event sleep for 5s and then send enter key - messsage box closed.
private void button1_Click(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
MessageBox.Show("Close this message!");
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
Thread.Sleep(5000);
SendKeys.SendWait("{Enter}");//or Esc
}
I think the cleanest way would be to implement you own message box form like
class MyMessageBox : Form {
private MyMessageBox currentForm; // The currently active message box
public static Show(....) { // same as MessageBox.Show
// ...
}
public static Show(...) { // define additional overloads
}
public static CloseCurrent() {
if (currentForm != null)
currentForm.Close();
}
// ...
}
In some of my larger projects, I found this approach useful also for other purposes (such as automatic logging of error messages etc.)
The second idea I have would be to use GetTopWindow()
(or maybe some other WIN32 function) to get the current top-level window of your application and send a WM_CLOSE
message to it.