Force to close MessageBox programmatically

后端 未结 11 1904
清酒与你
清酒与你 2020-12-03 07:21

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

相关标签:
11条回答
  • 2020-12-03 08:04

    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.

    0 讨论(0)
  • 2020-12-03 08:04

    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

    0 讨论(0)
  • 2020-12-03 08:06

    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);
    
    0 讨论(0)
  • 2020-12-03 08:06

    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.

    1. Keep the form handler and close it with:

      static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
      

      or

    2. 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.

    0 讨论(0)
  • 2020-12-03 08:08

    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
    }
    
    0 讨论(0)
  • 2020-12-03 08:08

    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.

    0 讨论(0)
提交回复
热议问题